Generalize failed-IP cooldown across all LoadBalance modes and make it configurable#2221
Merged
Merged
Conversation
…nfigurable Extract the failed-IP cooldown out of RoundRobinAddressSelector into a new, mode-independent FailedIpCooldownHolder that reorders a request's resolved addresses before a new connection so a recently-failed IP is briefly deprioritized. It now applies to any direct connection (DEFAULT mode included), not just ROUND_ROBIN. - Add FailedIpCooldownHolder (reorder/markFailed over bounded per-host state) - Reduce RoundRobinAddressSelector to pure rotation - Add failedIpCooldownEnabled (default true) and failedIpCooldownPeriod (default PT10S) config settings end-to-end - Wire the cooldown into NettyRequestSender for direct connections in any mode, feeding back TCP connect failures via the connector's failure listener - Split tests: keep rotation tests, add FailedIpCooldownHolderTest and FailedIpCooldownConfigTest
pavel-ptashyts
force-pushed
the
cooldown-refactoring
branch
from
July 1, 2026 10:03
7e95a29 to
4b7d44e
Compare
hyperxpro
approved these changes
Jul 18, 2026
hyperxpro
added a commit
that referenced
this pull request
Jul 18, 2026
Motivation: #2221 extended failed-IP cooldown support to all `LoadBalance` modes and made it configurable, but left three gaps. The end-to-end feedback loop in `DEFAULT` mode, from `markFailed` to IP reordering, was never exercised through the client, leaving regressions undetected. The configuration also accepted negative cooldown periods, silently disabling the feature, and enabling the cooldown with a `null` period in a custom config could cause `NettyRequestSender` construction to fail with an NPE. Modification: Add an end-to-end test that verifies `DEFAULT` mode deprioritizes a failed IP on subsequent connections using a multi-IP host and fresh connections. Reject negative cooldown periods with `IllegalArgumentException` while continuing to allow `null` (reset to the default) and `Duration.ZERO`. Guard `NettyRequestSender` against a `null` cooldown period when the feature is enabled, leaving the cooldown disabled instead of failing client construction. Result: The failed-IP cooldown behavior in `DEFAULT` mode is now covered end-to-end, ensuring regressions are detected. Invalid negative configuration now fails fast, and inconsistent custom configurations no longer cause client construction to fail.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The failed-IP cooldown (when a TCP connect to an IP fails, that IP is briefly
moved to the back of the failover order, then re-probed) previously lived inside
RoundRobinAddressSelectorand only ran inLoadBalance.ROUND_ROBINmode, witha hard-coded on/off and duration.
This PR extracts the cooldown into its own mode-independent component and applies
it to any direct connection —
DEFAULTmode included — so a recently-failedIP is deprioritized on the next new connection regardless of load-balancing mode.
It also exposes the feature through client config.
What changed
FailedIpCooldownHolder(netty/channel) — holds the cooldown logic(
reorder(host, addresses)+markFailed(host, address)) over bouThe failed-IP cooldown (when a TCP connect to an IP fails, that IP is briefly
moved to the back of the failover order, then re-probed) previously lived inside
RoundRobinAddressSelectorand only ran inLoadBalance.ROUND_ROBINa hard-coded on/off and duration.
This PR extracts the cooldown into its own mode-independent component and applies
it to any direct connection —
DEFAULTmode included — so a receIP is deprioritized on the next new connection regardless of load-balancing mode.
It also exposes the feature through client config.
What changed
FailedIpCooldownHolder(netty/channel) — holds the cooldown logic(
reorder(host, addresses)+markFailed(host, address)) over bounded per-hoststate.
reorderonly re-orders the address list (cooling IPs to the back); itnever drops an address, so failover always has somewhere to go.
RoundRobinAddressSelectoris reduced to pure round-robin rotation.loadBalance, wired end-to-endAsyncHttpClientConfig,DefaultAsyncHttpClientConfig+ Builder,AsyncHttpClientConfigDefaults, andahc-default.properties):isFailedIpCooldownEnabled()— defaulttruegetFailedIpCooldownPeriod()— defaultPT10SNettyRequestSenderapplies the cooldown for direct connections in bothmodes (round-robin: on top of rotation, before pinning the IP-aware
default: when ordering the resolved addresses for a new connection) and feeds
TCP connect failures back via the connector's existing failure listener.
Behavior change
With the default
failedIpCooldownEnabled=true,DEFAULTmode nowdeprioritizes an IP that just failed to connect when opening its next new
connection to a multi-IP host. This preserves round-robin's previous always-on
behavior and extends the same benefit to default mode. Set
failedIpCooldownEnabled=falseto restore the old default-mode behavior.Scope & limitations
Requestaddress; no proxy,or proxy bypassed for the host), keyed by the target host — matchin
round-robin eligibility. Proxied/CONNECT requests are unaffected.
cooldown only re-orders — authoritative liveness is still expected at the
DNS/resolver level. Per-host state is bounded (cap 4096) with arbitrary eviction.